package com.linking.third.party.manager;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.XML;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.borealis.common.utils.SignUtils;
import com.google.common.collect.Maps;
import com.linking.third.party.pojo.bo.ReceiptVerifyBO;
import com.linking.third.party.pojo.bo.UserVerifyBO;
import com.linking.third.party.pojo.bo.WeChatPayBO;
import com.linking.third.party.pojo.bo.WeChatPayResBO;
import com.linking.third.party.pojo.bo.WeChatPayVerifyBO;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.TreeMap;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author YaoWeiXin
 * @Date 2020/7/14 14:36
 * @Description 微信 管理类
 */
@Slf4j
public class WeChatManager {

  public static UserVerifyBO checkUserToken(String appId, String appSecret, String token) {
    // 1、组合参数
    String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$secret&code=$code&grant_type=authorization_code";
    // 2、请求微信验证code
    url = url.replace("$appid", appId).replace("$secret", appSecret).replace("$code", token).trim();
    String res = HttpUtil.get(url);
    if (StrUtil.isEmpty(res)) {
      return UserVerifyBO.ofFail();
    }
    // 3、解析返回值
    JSONObject result = JSON.parseObject(res);
    log.debug("WeChatManager checkUserToken res={},req={}", res, url);
    String errCode = "errcode";
    if (result.containsKey(errCode)) {
      return UserVerifyBO.ofFail();
    }
    String accessToken = result.getString("access_token");
    String refreshToken = result.getString("refresh_token");
    String openid = result.getString("openid");
    String unionId = result.getString("unionid");
    // 4、获取用户信息
    url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid;
    res = HttpUtil.get(url);
    JSONObject userInfo = null;
    if (StrUtil.isNotEmpty(res)) {
      userInfo = JSON.parseObject(res);
      if (userInfo.containsKey(errCode)) {
        userInfo = null;
      }
    }
    return UserVerifyBO.ofWeChat(accessToken, refreshToken, openid, unionId, userInfo);
  }

  public static WeChatPayResBO doPay(WeChatPayBO weChatPay) {
    // 降序排序
    Map<String, Object> data = new TreeMap<>(String::compareTo);

    String body = weChatPay.getAppName() + "-" + weChatPay.getProductDesc();
    data.put("body", body);
    data.put("trade_type", "APP");
    data.put("mch_id", weChatPay.getMchId());
    data.put("nonce_str", weChatPay.getOrderId());
    data.put("fee_type", "CNY");
    data.put("out_trade_no", weChatPay.getOrderId());
    data.put("total_fee", weChatPay.getAmount().multiply(new BigDecimal("100"))
        .setScale(0, RoundingMode.DOWN).toPlainString());
    data.put("appid", weChatPay.getAppId());
    data.put("notify_url", weChatPay.getNotifyUrl());
    data.put("spbill_create_ip", weChatPay.getClientIp());
    String sign = SignUtils.signKeyValue2(data, weChatPay.getSecret());

    StringBuilder reqBody = new StringBuilder("<xml><body>" + body + "</body>");
    for (String key : data.keySet()) {
      reqBody.append("<").append(key).append(">").append(data.get(key)).append("</").append(key)
          .append(">");
    }
    reqBody.append("<sign>").append(sign).append("</sign>").append("</xml>");
    String req = HttpUtil.post("https://api.mch.weixin.qq.com/pay/unifiedorder", reqBody.toString());
    cn.hutool.json.JSONObject res = XML.toJSONObject(req);
    String success = "SUCCESS";
    String returnCode = "return_code";
    String resultCode = "result_code";
    res = res.getJSONObject("xml");
    if (success.equals(res.getStr(returnCode)) && success.equals(res.getStr(resultCode))) {
      data.clear();
      String str = DateUtil.currentSeconds() + "";
      data.put("timestamp", str);
      data.put("noncestr", res.getStr("nonce_str"));
      data.put("partnerid", weChatPay.getMchId());
      data.put("prepayid", res.getStr("prepay_id"));
      data.put("package", "Sign=WXPay");
      data.put("appid", weChatPay.getAppId());
      sign = SignUtils.signKeyValue2(data, weChatPay.getSecret());
      data.put("paySign", sign + "");
      data.put("return_code", res.getStr("return_code"));
      return WeChatPayResBO.of(data);
    } else {
      return WeChatPayResBO.ofFail();
    }
  }

  /**
   * 票据验证
   *
   * @param weChatPayVerifyBO 微信票据验证参数
   * @return 票据验证结果
   */
  public static ReceiptVerifyBO receiptVerify(WeChatPayVerifyBO weChatPayVerifyBO) {
    // 1、校验签名
    Map<String, Object> params = Maps.newHashMap();
    for (String name : weChatPayVerifyBO.getParams().keySet()) {
      // 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
      params.put(name, weChatPayVerifyBO.getParams().getStr(name));
    }
    String mySign = SignUtils.signKeyValue2(params, weChatPayVerifyBO.getPublicKey());
    String sign = weChatPayVerifyBO.getParams().getStr("sign");
    if (!mySign.equals(sign)) {
      log.debug("receiptVerify sign fail:{},{}", mySign, sign);
      return ReceiptVerifyBO.ofFail();
    }
    // 2、取出参数
    String transactionId = weChatPayVerifyBO.getParams().getStr("transaction_id");
    String orderId = weChatPayVerifyBO.getParams().getStr("out_trade_no");
    String openid = weChatPayVerifyBO.getParams().getStr("openid");
    String productId = weChatPayVerifyBO.getParams().getStr("product_id");
    String resultCode = weChatPayVerifyBO.getParams().getStr("result_code");
    String success = "SUCCESS";
    if (!success.equals(resultCode)) {
      log.debug("receiptVerify resultCode fail:{},{}", resultCode,
          weChatPayVerifyBO.getParams().getStr("return_msg"));
      return ReceiptVerifyBO.ofFail();
    }
    return ReceiptVerifyBO.ofWeChat(true, transactionId, orderId);
  }
}
